package com.chatplus.application.common.util;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

public class MapUtils {

    @SuppressWarnings("unused")
    public static <K extends Comparable<? super K>, V> Map<K, V> sortByKeyAsc(Map<K, V> map) {
        Map<K, V> result = new LinkedHashMap<>();
        map.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
        return result;
    }

    @SuppressWarnings("unused")
    public static <K extends Comparable<? super K>, V> Map<K, V> sortByKeyDesc(Map<K, V> map) {
        Map<K, V> result = new LinkedHashMap<>();
        map.entrySet().stream().sorted(Map.Entry.<K, V>comparingByKey().reversed()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
        return result;
    }

    @SuppressWarnings("unused")
    public static <K, V extends Comparable<? super V>> Map<K, V> sortByValueAsc(Map<K, V> map) {
        Map<K, V> result = new LinkedHashMap<>();
        map.entrySet().stream().sorted(Map.Entry.comparingByValue()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
        return result;
    }

    @SuppressWarnings("unused")
    public static <K, V extends Comparable<? super V>> Map<K, V> sortByValueDesc(Map<K, V> map) {
        Map<K, V> result = new LinkedHashMap<>();
        map.entrySet().stream().sorted(Map.Entry.<K, V>comparingByValue().reversed()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
        return result;
    }

    @SuppressWarnings("unused")
    public static Map<String, Object> convertBean2Map(Object bean) throws Exception {
        Class<?> type = bean.getClass();
        HashMap<String, Object> returnMap = new HashMap<>(10);
        BeanInfo beanInfo = Introspector.getBeanInfo(type);
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        int i = 0, n = propertyDescriptors.length;
        while (i < n) {
            PropertyDescriptor descriptor = propertyDescriptors[i];
            String propertyName = descriptor.getName();
            if (!"class".equals(propertyName)) {
                Method readMethod = descriptor.getReadMethod();
                if (readMethod == null && descriptor.getPropertyType().equals(Boolean.class)) {
                    String booleanGetter = "is" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
                    for (Method method : bean.getClass().getDeclaredMethods()) {
                        if (method.getName().equals(booleanGetter) && (method.getName().equals(getBooleanGetterName4Property(propertyName)))) {
                                try {
                                    readMethod = method;
                                    descriptor.setReadMethod(method);
                                } catch (IntrospectionException e) {
                                    throw new IllegalStateException("Cannot set read method" + e);
                                }

                        }
                    }
                }
                Object result = Objects.requireNonNull(readMethod).invoke(bean);
                returnMap.put(propertyName, result);
            }
            i++;
        }
        return returnMap;
    }

    private static String getBooleanGetterName4Property(String propertyName) {
        if (propertyName == null || propertyName.isEmpty()) {
            return null;
        }
        return "is" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
    }

}
